package com.zkjl.protect_business.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.zkjl.protect_business.common.BaseException;
import com.zkjl.protect_business.common.Consts;
import com.zkjl.protect_business.common.Status;
import com.zkjl.protect_business.common.UserThreadLocal;
import com.zkjl.protect_business.dto.*;
import com.zkjl.protect_business.entity.Business;
import com.zkjl.protect_business.entity.Organization;
import com.zkjl.protect_business.entity.Permission;
import com.zkjl.protect_business.entity.User;
import com.zkjl.protect_business.repository.BusinessRepository;
import com.zkjl.protect_business.repository.OrganizationRepository;
import com.zkjl.protect_business.repository.PermissionRepository;
import com.zkjl.protect_business.repository.UserRepository;
import com.zkjl.protect_business.service.*;
import com.zkjl.protect_business.utils.QueryUtil;
import com.zkjl.protect_business.utils.RedisUtil;
import com.zkjl.protect_business.vo.RouteVO;
import com.zkjl.protect_business.vo.UserOnlineVO;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.*;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.zkjl.protect_business.common.Consts.*;
import static com.zkjl.protect_business.common.Status.*;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author jr
 * @since 2020-06-17
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    ModelMapper modelMapper;
    @Autowired
    private BCryptPasswordEncoder encoder;
    @Autowired
    OrganizationService organizationService;
    @Autowired
    UserRepository userRepository;
    @Autowired
    PermissionRepository permissionRepository;
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    BusinessService businessService;
    @Autowired
    BusinessRepository businessRepository;
    @Autowired
    PermissionService permissionService;

    @Autowired
    LogService logService;

    @Autowired
    RedisUtil redisUtil;

    @Override
    public User save(UserDTO userDTO) {

        User user = modelMapper.map(userDTO, User.class);

        //用户名不能重复
        String userName = user.getUserName();
        User user1 = userRepository.findByUserName(userName);
        if (user1 != null) {
            throw new BaseException(Status.DATA_EXIST.getCode(), "用户名已存在，请修改后重试！");
        }

        //保存权限信息
        List<String> permissionIds = userDTO.getPermissionIds();
        if (CollUtil.isNotEmpty(permissionIds)) {
            List<Permission> permissions = permissionRepository.findAllByIdIn(permissionIds);
            user.setPermissions(permissions);
        }

        user.setId(IdUtil.simpleUUID());
        String passWord = user.getPassWord();
        if (StringUtils.isBlank(passWord)) {
            user.setPassWord(encoder.encode("123456"));
        } else {
            user.setPassWord(encoder.encode(passWord));
        }
        user.setBaseInfo();

        String orgId = user.getOrgId();
        Organization organization = organizationService.get(orgId);
        String orgName = organization.getOrgName();
        user.setOrg(orgName);
        user.setIfEnable(true);

        User save = userRepository.save(user);
        logService.save("用户", user.getRealName(), OPERATION_ADD);

        return save;
    }

    @Override
    public PageImpl page(PageBaseDTO pageBaseDTO, SortDTO sortDTO) {

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        Pageable pageable = QueryUtil.build(qb, queryBuilder, pageBaseDTO, sortDTO, User.class);


        //只能获取当前机构下的文档
        List<String> list = organizationService.listChildrenIdsAndOneself(UserThreadLocal.getOrgId());
        if (CollUtil.isEmpty(list)) {
            return new PageImpl(null, pageable, 0);
        }
        qb.filter(new TermsQueryBuilder("org_id",list));
        queryBuilder.withQuery(qb);

        SearchHits<User> search1 = elasticsearchRestTemplate.search(queryBuilder.build(), User.class);
        List<User> collect = search1.stream().map(SearchHit::getContent).collect(Collectors.toList());
        long total = search1.getTotalHits();


        PageImpl page = new PageImpl(collect, pageable, total);

        return page;
    }

    @Override
    public User update(String id, UserDTO userDTO) {

        User user = get(id);
        Boolean ifEnable = userDTO.getIfEnable();
        if (ifEnable != null) {
            user.setIfEnable(ifEnable);
        }

        String userName = userDTO.getUserName();
        if (StringUtils.isNotBlank(userName) && !user.getUserName().equals(userName)) {
            user.setUserName(userName);
            User byUserName = userRepository.findByUserName(userName);
            if (byUserName != null) {
                throw new BaseException(DATA_EXIST.getCode(), "用户名已存在，请更换后重试！");
            }
        }
        String realName = userDTO.getRealName();
        if (StringUtils.isNotBlank(realName)) {
            user.setRealName(realName);
        }

        //保存权限信息
        List<String> permissionIds = userDTO.getPermissionIds();
        if (CollUtil.isNotEmpty(permissionIds)) {
            List<Permission> permissions = permissionRepository.findAllByIdIn(permissionIds);
            user.setPermissions(permissions);
        }

        String orgId = userDTO.getOrgId();
        if (StringUtils.isNotBlank(orgId)) {
            Organization organization = organizationService.get(orgId);
            String orgName = organization.getOrgName();
            user.setOrg(orgName);
            user.setOrgId(orgId);
        }

        String passWord = userDTO.getPassWord();
        if (StringUtils.isNotBlank(passWord)) {
            user.setPassWord(encoder.encode(passWord));
        }


        user.setUpdateTime(System.currentTimeMillis());

        User save = userRepository.save(user);
        logService.save("用户", user.getRealName(), OPERATION_EDIT);

        return save;
    }

    @Override
    public User get(String id) {

        Optional<User> repository = userRepository.findById(id);
        if (!repository.isPresent()) {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "未找到用户信息！");
        }

        User user = repository.get();

        return user;
    }

    @Override
    public Boolean updatePassWord(UpdatePassWordDTO updatePassWordDTO) {

        String userId = UserThreadLocal.getUserId();

        User user = get(userId);

        String newPassWord = updatePassWordDTO.getNewPassWord();
        String oldPassWord = updatePassWordDTO.getOldPassWord();

        String passWord = user.getPassWord();

        boolean matches = encoder.matches(oldPassWord, passWord);
        if (!matches) {
            throw new BaseException(BAD_REQUEST.getCode(), "原始密码错误");
        }


        user.setPassWord(encoder.encode(newPassWord));

        userRepository.save(user);

        logService.save("用户", user.getRealName(), OPERATION_UPDATE_PASSWORD);

        return true;
    }

    @Override
    public User updateMyInfo(UpdateUserDTO updateUserDTO) {

        String userId = UserThreadLocal.getUserId();
        User user = get(userId);
        user.setPhone(updateUserDTO.getPhone());
        user.setAge(updateUserDTO.getAge());
        user.setEmail(updateUserDTO.getEmail());
        user.setPhoto(updateUserDTO.getPhoto());

        User save = userRepository.save(user);
        return save;
    }

    @Override
    public User getByOrgId(String orgId) {

        User user = userRepository.findByOrgId(orgId);

        return user;
    }

    @Override
    public Boolean del(String id) {

        if (id.equals(UserThreadLocal.getUserId())) {
            throw new BaseException(BAD_REQUEST.getCode(), "不能删除自己！");
        }

        User user = get(id);
        logService.save("用户", user.getRealName(), OPERATION_DEL);
        userRepository.deleteById(id);

        return true;
    }

    @Override
    public Boolean updateOrgInfo(String orgId, String orgName) {

        List<User> users = userRepository.findAllByOrgId(orgId);

        if (CollUtil.isEmpty(users)) {
            return true;
        }

        users.stream().forEach(user -> {
            user.setOrg(orgName);
            userRepository.save(user);
        });


        return null;
    }

    @Override
    public List<RouteVO> getUserRoute() {

        String userId = UserThreadLocal.getUserId();
        User user = get(userId);

        //存放管理员所有权限
        String sysRoleName = user.getSysRoleName();
        if (ADMIN.equals(sysRoleName)) {
            List<Permission> list = permissionService.list();
            user.setPermissions(list);
            user = userRepository.save(user);
        }

        //用户拥有的所有权限
        List<Permission> permissions = user.getPermissions();

        if (CollUtil.isEmpty(permissions)) {
            throw new BaseException(DATA_NOT_EXIST.getCode(), "未找到用户权限信息！");
        }

        //用户拥有的所有页面id
        List<String> businessIds = permissions.stream().filter(permission -> StringUtils.isNotBlank(permission.getPermission()) && permission.getPermission().startsWith("page:")).
                map(permission -> {
                    String permission1 = permission.getPermission();
                    String[] split = permission1.split(":");
                    String s = split[1];
                    return s;
                }).collect(Collectors.toList());

        List<Business> businesses = businessRepository.findAllByIdInOrderByCreateTimeAsc(businessIds);
        CollUtil.removeNull(businesses);
        businesses = CollUtil.distinct(businesses);

        List<Business> finalBusinesses = businesses;

        List<RouteVO> collect = businesses.stream().filter(business -> StringUtils.isBlank(business.getPid())).map(business -> {

            String id = business.getId();
            String routing = business.getRouting();
            String name = business.getName();
            RouteVO routeVO = new RouteVO();
            routeVO.setAuthority("*");
            routeVO.setSort(business.getSort());

            routeVO.setName(name);
            String pinyin = PinyinUtil.getPinyin(name, "");
            routeVO.setPath(pinyin);
            routeVO.setId(id);
            routeVO.setRouter(routing);
            routeVO.setInvisible(business.getInvisible());
            if (StringUtils.isBlank(routing)) {

                routeVO.setRouter(pinyin);
            }
            routeVO.setChildren(getChildren(id, finalBusinesses));

            return routeVO;
        }).collect(Collectors.toList());

        List<RouteVO> result = new ArrayList<>();

        RouteVO routeVO = new RouteVO();
        routeVO.setRouter("dashboard");
        routeVO.setName("控制台");

        RouteVO routeVO1 = new RouteVO();
        routeVO1.setName("工作台");
        routeVO1.setRouter("workplace");
        routeVO.setChildren(Lists.newArrayList(routeVO1));


        RouteVO routeVO2 = new RouteVO();
        routeVO2.setName("其他");
        routeVO2.setInvisible(true);
        routeVO2.setAuthority("*");
        routeVO2.setPath("qita");
        routeVO2.setRouter("businessGroup");
        routeVO2.setChildren(getChildren(businesses));

        result.add(routeVO);
        result.add(routeVO2);
        result.addAll(collect);

        return result;


    }

    @Override
    public List<UserOnlineVO> getUserOnlines(String orgId) {

        List<User> users = userRepository.findAllByOrgId(orgId);
        if (CollUtil.isEmpty(users)) {
            return null;
        }

        //所有在线的用户名
        List<String> all = redisUtil.findAll(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR);

        List<UserOnlineVO> collect = users.stream().map(user -> {
            String userName = user.getUserName();
            UserOnlineVO userOnlineVO = new UserOnlineVO();
            userOnlineVO.setAccount(userName);
            userOnlineVO.setName(user.getRealName());
            userOnlineVO.setPhone(user.getPhone());
            userOnlineVO.setUserId(user.getId());
            if (all.contains(userName)) {
                userOnlineVO.setOnline("在线");
            } else {
                userOnlineVO.setOnline("离线");
            }

            return userOnlineVO;

        }).collect(Collectors.toList());
        return collect;
    }


    /**
     * 获取三级业务
     * @param businesses
     * @return
     */
    public List<RouteVO> getChildren(List<Business> businesses){

        List<Business> businesses1 = businesses.stream().filter(business -> {
            //第三级分类权限给*
            String path = business.getPath();
            if (StringUtils.isNotBlank(path)) {
                String[] split = path.split("/");
                if (split.length > 2) {
                    return true;
                }
            }
            return false;

        }).collect(Collectors.toList());



        if (CollUtil.isNotEmpty(businesses1)) {

            List<RouteVO> collect = businesses1.stream().map(business -> {
                String id = business.getId();
                String routing = business.getRouting();
                String name = business.getName();
                RouteVO routeVO = new RouteVO();

                routeVO.setName(name);
                String pinyin = PinyinUtil.getPinyin(name, "");
                routeVO.setPath(pinyin);
                routeVO.setId(id);
                Map<String, Object> authority = new HashMap<>();
                authority.put("permission", id);
                routeVO.setAuthority(authority);
                routeVO.setRouter(routing);
                routeVO.setInvisible(business.getInvisible());

                if (StringUtils.isBlank(routing)) {
                    routeVO.setRouter(pinyin);
                }
                routeVO.setChildren(getChildren(id, businesses));
                return routeVO;
            }).collect(Collectors.toList());

            return collect;

        }
        return null;


    }


    /**
     * 获取子路由
     *
     * @param pid
     * @return
     */
    public List<RouteVO> getChildren(String pid, List<Business> businesses) {

        List<Business> businesses1 = businesses.stream().filter(business -> {

            boolean equals = pid.equals(business.getPid());
            boolean islevel2 = true;
            //第三级分类权限给*
            String path = business.getPath();
            if (StringUtils.isNotBlank(path)) {
                String[] split = path.split("/");
                if (split.length > 2) {
                    islevel2 = false;
                }

            }

            return equals && islevel2;


        }).collect(Collectors.toList());


        if (CollUtil.isNotEmpty(businesses1)) {

            List<RouteVO> collect = businesses1.stream().map(business -> {
                String id = business.getId();
                String routing = business.getRouting();
                String name = business.getName();
                RouteVO routeVO = new RouteVO();
                Map<String, Object> authority = new HashMap<>();

                //第三级分类权限给*
                authority.put("permission", id);
                routeVO.setAuthority(authority);

                routeVO.setName(name);
                String pinyin = PinyinUtil.getPinyin(name, "");
                routeVO.setPath(pinyin);
                routeVO.setId(id);
                routeVO.setSort(business.getSort());
                routeVO.setRouter(routing);
                routeVO.setInvisible(business.getInvisible());

                if (StringUtils.isBlank(routing)) {
                    routeVO.setRouter(pinyin);
                }
                routeVO.setChildren(getChildren(id, businesses));
                return routeVO;
            }).collect(Collectors.toList());

            return collect;

        }

        return null;

    }

}
